package com.alibaba.sdk.config;

import com.alibaba.sdk.enums.BaseEnum;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;

/**
 * spring web请求中参数枚举转换
 *
 * @ writer Shawn(Shawn_0217@163.com)
 * @ date & time 2021/5/31 21:30
 * @ company alibaba
 */
@Configuration
public class SpringWebEnumConverter implements ConverterFactory<String, BaseEnum> {

    /**
     * 初始化弱键值对
     */
    public static final Map<Class, Converter> converterMap = new WeakHashMap<>();

    @Override
    public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
        Converter result = converterMap.get(targetType);
        if(result == null) {
            result = new IntegerStrToEnum<T>(targetType);
            converterMap.put(targetType, result);
        }
        return result;
    }

    /**
     * 枚举编号转枚举内部类
     *
     * @param <T>
     */
    static class IntegerStrToEnum<T extends BaseEnum> implements Converter<String, T> {

        /**
         * 全局变量
         */
        private final Class<T> enumType;

        /**
         * 初始化转换器键值对集合
         */
        private Map<String, T> enumMap = new HashMap<>();

        /**
         * 有参构造器
         *
         * @param enumType
         */
        public IntegerStrToEnum(Class<T> enumType) {
            this.enumType = enumType;
            T[] enums = enumType.getEnumConstants();
            for(T e : enums) {
                enumMap.put(e.getCode() + "", e);
            }
        }

        @Override
        public T convert(String source) {
            T result = enumMap.get(source);
            if(result == null) {
                throw new IllegalArgumentException("No element matches " + source);
            }
            return result;
        }
    }

    /**
     * 枚举类的转换器工厂
     *
     * @return
     */
    @Bean
    public WebMvcConfigurer enumConfig() {
        return new WebMvcConfigurer() {
            @Override
            public void addFormatters(FormatterRegistry registry) {
                registry.addConverterFactory(new SpringWebEnumConverter());
            }
        };
    }
}
